import collections
import time
import threading

class Cache(object):

    def __init__(self):
        self._tempstore = collections.OrderedDict()
        self._store = collections.OrderedDict()
        self._templose = {}
        self._lose = {}
        self._max = 10 * 1000
        self._losetime = 90 * 60
        self.lock = threading.Lock()
        self.__loop__()

    def __loop__(self):
        aThread = threading.Thread(target=self.__clearlose__)
        aThread.setDaemon(True)
        aThread.start()
        aTimer = threading.Timer(self._losetime, self.__loop__)
        aTimer.setDaemon(True)
        aTimer.start()

    def clear(self):
        if self.lock.acquire():
            self._store.clear()
            self._lose.clear()
            self._tempstore.clear()
            self._templose.clear()
            print("clear")
            self.lock.release()

    def __clearlose__(self):
        dels = []
        for key,val in self._lose.items():
            if time.time() - val <= self._losetime:
                continue
            dels.append(key)
        if len(dels) == 0:
            return
        if self.lock.acquire():
            for key in dels:
                self._delete(key)
            self._mergetemp()
            self.lock.release()

    def _mergetemp(self):
        self._store.update(self._tempstore)
        self._lose.update(self._templose)
        self._tempstore.clear()
        self._templose.clear()
        self._checkmax()

    def exist(self, key):
        key = self.generatorkey(key)
        return self._exist(key)

    def _exist(self, key):
        if self.checkkey(key):
            return key in self._store
        else:
            return False

    def generatorkey(self, origin):
        if origin is None:
            return ""
        else:
            return str(hash(origin))

    def checkkey(self, key):
        return isinstance(key, str) and key != ""

    def checkvalue(self, value):
        return isinstance(value, str) and value != ""

    def _cache(self, key, value):
        if not self.checkkey(key) or not self.checkvalue(value):
            return False
        self._update(key, value)

        return True

    def cache(self, key, value):
        key = self.generatorkey(key)
        return self._cache(key, value)

    def _update(self, key, value):
        if self.lock.locked():
            self._tempstore[key] = value
            self._templose[key] = time.time()
        else:
            self.lock.acquire()
            self._store[key] = value
            self._store.move_to_end(key)
            self._lose[key] = time.time()
            self._checkmax()
            self.lock.release()

    def value(self, key):
        key = self.generatorkey(key)
        if not self.checkkey(key):
            return ""
        if key in self._store:
            return self._store.get(key, "")
        else:
            return self._tempstore.get(key, "")

    def _checkmax(self):
        overnum = len(self._store) - self._max
        if overnum <= 0:
            return
        keys = self._store.keys()[0:overnum]
        for key in keys:
            self._delete(key)

    def _delete(self, key):
        self._store.__delitem__(key)
        self._lose.__delitem__(key)